import fs from 'fs';
import path from 'path';
// 这里开始考虑cluster的模式方便部署

class TeConfigMgr {
    private static _inst: TeConfigMgr;
    static get inst() {
        if (!this._inst) this._inst = new TeConfigMgr();
        return this._inst;
    }

    static get(v: string, int: boolean = false) {
        if (int) {
            return parseInt(this.inst.get(v));
        }
        return this.inst.get(v)
    }

    /**
     * 零时的调整配置，重启后失效
     * @param k 
     * @param v
     */
    static set(k: string, v: any) {
        this.inst._tmpValue[k] = v;
        this.inst.set(k, v);
    }

    static has(v: string) {
        return this.inst.has(v);
    }

    static default(d: { [key: string]: any }) {
        return this.inst.registDefault(d)
    }

    private _tmpValue: { [key: string]: any } = {};
    private _configValue: { [key: string]: any } = {};
    private _defaultValue: { [key: string]: any } = {};
    private _filePath: string = '';
    constructor() {
        this._filePath = path.join(process.cwd(), 'config.json');
        fs.watchFile(this._filePath, this._watchFile.bind(this));
        this._loadFile();
    }

    changeFile(file: string) {
        fs.unwatchFile(this._filePath);
        this._filePath = file;
        fs.watchFile(this._filePath, this._watchFile.bind(this));
        this._configValue = {};
        this._loadFile();
    }

    private _loadFile() {
        try {
            var jt = fs.readFileSync(this._filePath);
            this._configValue = JSON.parse(jt.toString());
            // 这里需要把特殊的配置项目设置进入
            for (let key in this._tmpValue) {
                this.set(key, this._tmpValue[key])
            }
        }
        catch (e) {
        }
    }

    private _watchFile(curr: fs.Stats, prev: fs.Stats) {
        if (prev.ctime.getTime() == 0 && curr.ctime.getTime() != 0) {
            //console.log('文件被创建!');
            this._loadFile();
        } else if (curr.ctime.getTime() == 0) {
            // console.log('文件被删除!');
            // 文件删除了，但是配置先不要响应删除操作了

        } else if (curr.mtime.getTime() != prev.mtime.getTime()) {
            // console.log('文件有修改');
            this._loadFile();
        }
    }


    public registDefault(def: { [key: string]: any }) {
        this._defaultValue = Object.assign(this._defaultValue, def);
    }

    private _get(srcObj: Object, key: string) {
        var arr = key.split('.');
        var tObj: any = srcObj;
        for (var i = 0; i < arr.length; i++) {
            if (!tObj) return null;
            tObj = tObj[arr[i]];
        }

        return tObj;
    }

    public get<T>(key: string): T {
        var ret: any = this._get(this._configValue, key);
        if (ret == null) ret = this._get(this._defaultValue, key);
        if (ret == null) ret = 0;
        return ret;
    }

    public set(key: string, v: any) {
        if (this._set(this._configValue, key, v, false)) {
            return
        }
        this._set(this._defaultValue, key, v, true)
    }

    // 设置新的属性上去，如果没有就不设置了
    private _set(srcObj: any, key: string, v: any, force: boolean) {
        var arr = key.split('.');
        var tObj: any = srcObj;
        for (var i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                tObj[arr[i]] = v;
            }
            else {
                if (tObj[arr[i]] == undefined) {
                    if (force == false) return false
                    else {
                        tObj[arr[i]] = {}
                    }
                }
                tObj = tObj[arr[i]];
            }
        }

        return true
    }

    private _has(srcObj: Object, key: string) {
        var arr = key.split('.');
        var tObj: any = srcObj;
        for (var i = 0; i < arr.length; i++) {
            if (!tObj || !tObj.hasOwnProperty(arr[i])) return false;
            tObj = tObj[arr[i]];
        }

        return true;
    }

    public has(key: string): boolean {
        // this._use_key_log(key);
        // 先找动态的
        // 再找配置的
        // 最后找默认的
        var ret: boolean = false;
        if (ret == false) ret = this._has(this._configValue, key);
        if (ret == false) ret = this._has(this._defaultValue, key);
        if (ret == false) ret = false;
        return ret;
    }

    /**
     * 制作json配置用的模板文件，或者说把配置用的js文件转成json文件，主要是json是不能有注释的
     */
    public createTemplateJson() {
        // 这里把defalut的生成一个json的就可以了
        var jsonFile = JSON.stringify(this._defaultValue, null, 4);

        var pd = path.parse(this._filePath)

        fs.writeFileSync(path.join(pd.dir, 'config.templete'), jsonFile);
    }
}

var instance = new TeConfigMgr();
export var ConfigMgr = {
    name: 'ConfigMgr',
    /**
     * 获取配置项 支持 a.b.c
     * @param {string} v 
     * @param {boolean} int 
     */
    get: function (v: string, int: boolean = false): any {
        return (int ? parseInt(instance.get<string>(v)) : instance.get(v)) as any
    },
    set: function (k: string, value: any) {
        return instance.set(k, value)
    },
    /**
     * 检查配置项是否存在 支持 a.b.c
     * @param v 
     */
    has: function (v: string) {
        return instance.has(v);
    },
    /**
     * 设置默认配置项
     * @param d 
     */
    default: function (d: { [key: string]: any }) {
        return instance.registDefault(d)
    },
    /**
     * 切换配置文件
     * @param path 
     */
    changeFile: function (path: string) {
        return instance.changeFile(path);
    }
}

export default ConfigMgr;
